﻿using System.Collections.Concurrent;
using System.Reflection;
using Dyao.Book.Contract;

namespace Dyao.Book.Application
{

    public class TaskCenterRequestParamsSerializerForDateFilterService : TaskCenterRequestParamsSerializerService
    {
        private static readonly ConcurrentDictionary<Type, DateFilterPropertyAnalysisResultModel> _cacheInfos = new ConcurrentDictionary<Type, DateFilterPropertyAnalysisResultModel>();
        private static readonly Type[] _targetPropTypes = new Type[] { typeof(DateTime), typeof(DateTime?) };

        /// <summary>
        /// 默认的JSON字符串反序列化方法
        /// </summary>
        /// <param name="type"></param>
        /// <param name="str"></param>
        /// <returns></returns>
        public override object DefaultJsonDeserialize(Type type, object str)
        {
            var model = base.DefaultJsonDeserialize(type, str);

            #region == 对日期类型的属性值做特殊处理 ==

            var analysisInfo = getPropertyAnalysisInfo(type);

            if (analysisInfo.IsAnyDateFilterProperty)
            {
                foreach (var property in analysisInfo.StartDatePropertyInfos)
                {
                    var dtime = property.GetValue(model, null);
                    if (dtime != null)
                    {
                        var newValue = ((DateTime)dtime).Date;
                        property.SetValue(model, newValue);
                    }
                }

                foreach (var property in analysisInfo.EndDatePropertyInfos)
                {
                    var dtime = property.GetValue(model, null);
                    if (dtime != null)
                    {
                        var isLastSecondOfToday = property.GetCustomAttribute<DateFilterEndAttribute>(true)?.IsLastSecondOfToday ?? false;
                        var newValue = ((DateTime)dtime).Date.AddDays(1).AddSeconds(isLastSecondOfToday ? (-1) : 0);
                        property.SetValue(model, newValue);
                    }
                }
            }

            #endregion

            return model;
        }

        /// <summary>
        /// 从缓存中获取一个类型属性解析结果
        /// <para>解析Model中的属性信息：包含标记为 <see cref="DateFilterStartAttribute"/> 与 <see cref="DateFilterEndAttribute"/> 的属性信息集合</para>
        /// </summary>
        private static DateFilterPropertyAnalysisResultModel getPropertyAnalysisInfo(Type modelType)
        {
            return _cacheInfos.GetOrAdd(modelType, t =>
            {
                var propertyInfos = t.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                     .Where(it => it.CanRead && it.CanWrite)
                                     .Where(it => _targetPropTypes.Contains(it.PropertyType));

                var startDatePropertyInfos = propertyInfos.Where(it => it.GetCustomAttribute<DateFilterStartAttribute>(true) != null);
                var endDatePropertyInfos = propertyInfos.Where(it => it.GetCustomAttribute<DateFilterEndAttribute>(true) != null);

                return new DateFilterPropertyAnalysisResultModel()
                {
                    IsAnyDateFilterProperty = startDatePropertyInfos.Any() || endDatePropertyInfos.Any(),
                    StartDatePropertyInfos = startDatePropertyInfos.ToArray(),
                    EndDatePropertyInfos = endDatePropertyInfos.ToArray(),
                };
            });
        }
    }
}
